package com.roger.ndtplayer.commom.api

import com.franmontiel.persistentcookiejar.PersistentCookieJar
import com.franmontiel.persistentcookiejar.cache.SetCookieCache
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor
import com.roger.ndtplayer.App
import com.roger.ndtplayer.commom.USER_TOKEN
import com.roger.ndtplayer.commom.core.MMKVHelper
import com.roger.ndtplayer.util.LogUtils
import io.reactivex.schedulers.Schedulers
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.logging.HttpLoggingInterceptor
import okio.Buffer
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.io.IOException
import java.util.*
import java.util.concurrent.TimeUnit

/**
 * Retrofit网络请求工具
 */
object RetrofitClient {

    /**Cookie*/
    private val cookiePersistor = SharedPrefsCookiePersistor(App.instance)
    private val cookieJar = PersistentCookieJar(SetCookieCache(), cookiePersistor)

    /**log**/
    private val logger = HttpLoggingInterceptor.Logger {
        LogUtils.e(this::class.simpleName.toString(), it)
    }
    private val logInterceptor = HttpLoggingInterceptor(logger).apply {
        level = HttpLoggingInterceptor.Level.BODY
    }

    internal class LogInterceptor : Interceptor {
        @Throws(IOException::class)
        override fun intercept(chain: Interceptor.Chain): Response {
            val oldRequest: Request = chain.request()
            var newRequestBuild: Request.Builder? = null
            val method = oldRequest.method
            var postBodyString = ""
            if ("POST" == method) {
                val oldBody = oldRequest.body
                if (oldBody is FormBody) {
                    val formBodyBuilder = FormBody.Builder()
//                    formBodyBuilder.add("trace_id", UUID.randomUUID().toString())
//                    formBodyBuilder.add("token", MMKVHelper.getMMKVValue(USER_TOKEN, ""))
                    newRequestBuild = oldRequest.newBuilder()
                    val formBody: RequestBody = formBodyBuilder.build()
                    postBodyString = bodyToString(oldRequest.body)
                    postBodyString += (if (postBodyString.isNotEmpty()) "&" else "") + bodyToString(
                        formBody
                    )
                    newRequestBuild.post(
                        RequestBody.create(
                            "application/x-www-form-urlencoded;charset=UTF-8".toMediaTypeOrNull(),
                            postBodyString
                        )
                    )
                } else if (oldBody is MultipartBody) {
                    val oldPartList: List<MultipartBody.Part> = oldBody.parts
                    val builder = MultipartBody.Builder()
                    builder.setType(MultipartBody.FORM)
                    val requestBody2 =
                        RequestBody.create(
                            ("text/plain").toMediaTypeOrNull(),
                            UUID.randomUUID().toString()
                        )
                    for (part in oldPartList) {
                        builder.addPart(part)
                        postBodyString += """
                        ${bodyToString(part.body)}
                        
                        """.trimIndent()
                    }
                    postBodyString += """
                    ${bodyToString(requestBody2)}
                    
                    """.trimIndent()
                    builder.addPart(requestBody2)
                    newRequestBuild = oldRequest.newBuilder()
                    newRequestBuild.post(builder.build())
                } else {
                    newRequestBuild = oldRequest.newBuilder()
                }
            } else {
                // 添加新的参数
                val commonParamsUrlBuilder: HttpUrl.Builder = oldRequest.url
                    .newBuilder()
                    .scheme(oldRequest.url.scheme)
                    .host(oldRequest.url.host)
//                    .addQueryParameter("trace_id", UUID.randomUUID().toString())
//                    .addQueryParameter("token", MMKVHelper.getMMKVValue(USER_TOKEN, ""))
                newRequestBuild = oldRequest.newBuilder()
                    .method(oldRequest.method, oldRequest.body)
                    .url(commonParamsUrlBuilder.build())
            }
            val newRequest: Request = newRequestBuild
                .addHeader("Accept", "application/json")
                .addHeader("Accept-Language", "zh")
                .addHeader("token", MMKVHelper.getMMKVValue(USER_TOKEN, ""))
                .build()
            val startTime = System.currentTimeMillis()
            val response: Response = chain.proceed(newRequest)
            val endTime = System.currentTimeMillis()
            val duration = endTime - startTime
            val mediaType = response.body!!.contentType()
            val content = response.body!!.string()
            val httpStatus = response.code
            val logSB = StringBuilder()
            logSB.append("-------start:$method|")
            logSB.append("$newRequest\n|")
            logSB.append(
                if (method.equals(
                        "POST",
                        ignoreCase = true
                    )
                ) "post参数{$postBodyString}\n|" else ""
            )
            logSB.append("httpCode=$httpStatus;Response:$content\n|")
            logSB.append("----------End:" + duration + "毫秒----------")

            if (logSB.toString().length > 4000) {
                LogUtils.e(logSB.toString().subSequence(0, 4000).toString())
                LogUtils.e("------------------------------------------------------------")
                LogUtils.e(logSB.toString().subSequence(4000, logSB.toString().length).toString())
            } else {
                LogUtils.e(logSB.toString())
            }
            return response.newBuilder()
                .body(ResponseBody.create(mediaType, content))
                .build()
        }

        private fun bodyToString(request: RequestBody?): String {
            return try {
                val buffer = Buffer()
                if (request != null) request.writeTo(buffer) else return ""
                buffer.readUtf8()
            } catch (e: IOException) {
                "did not work"
            }
        }
    }

    /**OkhttpClient*/
    private val okHttpClient = OkHttpClient.Builder()
        .callTimeout(10, TimeUnit.SECONDS)
        .cookieJar(cookieJar)
        .addInterceptor(LogInterceptor())
//        .addNetworkInterceptor(logInterceptor)
        .build()

    /**Retrofit*/
    private val retrofit = Retrofit.Builder()
        .client(okHttpClient)
        .baseUrl(ApiService.BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
        .build()

    /**ApiService*/
    val apiService: ApiService = retrofit.create(ApiService::class.java)

    /**清除Cookie*/
    fun clearCookie() = cookieJar.clear()

    /**是否有Cookie*/
    fun hasCookie() = cookiePersistor.loadAll().isNotEmpty()
}